import platform
import subprocess

import pandas as pd
import wx
import wx.html2 as webview
import os
from datetime import datetime
import threading
import time
import wx.lib.newevent as ne
import wx.adv

import config
from gui.gui_logic import load_tasks

# from backtrader_extends.engine import run_task
# from common.dataloader_duckdb import DuckdbLoader
# from config import DATA_REPORTS, DATA_TASKS

#from gui.backtest_visualizer import BacktestVisualizer

# 自定义事件，用于线程与主线程通信
BacktestProgressEvent, EVT_BACKTEST_PROGRESS = ne.NewEvent()
BacktestCompleteEvent, EVT_BACKTEST_COMPLETE = ne.NewEvent()

class BacktestThread(threading.Thread):
    """回测线程"""
    def __init__(self, panel, strategy, start_date, end_date, benchmark):
        super().__init__()
        self.panel = panel
        self.strategy = strategy
        self.start_date = start_date
        self.end_date = end_date
        self.benchmark = benchmark
        self._stop_event = threading.Event()

    def notify(self, progress):
        wx.PostEvent(self.panel, BacktestProgressEvent(progress=progress))
    
    def run(self):
        """执行回测逻辑"""
        #try:
        task = local_tasks[self.strategy]
        task.benchmark = self.benchmark
        task.start_date = self.start_date
        task.end_date = self.end_date

        from common.api import backtest
        data = backtest(task)['quotes']
        df = pd.DataFrame(data)
        df.set_index('date', inplace=True)
        df.index  = pd.to_datetime(df.index)

        returns = df['策略'].pct_change()
        benchmark_rets = df['benchmark'].pct_change()



        file_name = config.DATA_REPORTS.joinpath(task.name + '.html').resolve()
        benchmark = '510300.SH'
        # loader = DuckdbLoader(path=config.DATA_ETF_QUOTES, symbols=[benchmark],
        #                       cols=['close'], start_date=task.date.start_date, end_date=task.date.end_date)
        # benchmark_rets = loader.df['close'].pct_change()
        import quantstats
        import matplotlib.pyplot as plt
        # 设置 Matplotlib 的中文字体
        plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
        plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

        #print(file_name)
        quantstats.reports.html(returns, download_filename=file_name, output=file_name,
                                title='AI量化实验室', strategy_title=task.name, benchmark=benchmark_rets,
                                benchmark_title='基准')




        # 发送完成事件
        wx.PostEvent(self.panel, BacktestCompleteEvent(strategy=self.strategy))
            
        # except Exception as e:
        #     wx.CallAfter(wx.MessageBox, f"回测出错: {str(e)}", "错误", wx.OK|wx.ICON_ERROR)
    
    def stop(self):
        """停止回测"""
        self._stop_event.set()

from config import DATA_TASKS
local_tasks = load_tasks(DATA_TASKS.resolve())

class BacktestPanel(wx.Panel):
    def __init__(self, parent):
        super().__init__(parent)
        
        # 当前回测线程
        self.backtest_thread = None

        
        # 主布局
        self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
        
        # 左侧面板 - 回测条件
        self.left_panel = wx.Panel(self)
        left_sizer = wx.BoxSizer(wx.VERTICAL)
        
        # 策略选择器
        strategy_box = wx.StaticBox(self.left_panel, label="策略选择")
        strategy_sizer = wx.StaticBoxSizer(strategy_box, wx.VERTICAL)
        self.strategy_choice = wx.Choice(strategy_box, choices=list(local_tasks.keys()))
        # 默认选择第一项（索引为0）


        # 绑定策略选择事件
        self.strategy_choice.Bind(wx.EVT_CHOICE, self.on_strategy_changed)

        strategy_sizer.Add(self.strategy_choice, 0, wx.EXPAND|wx.ALL, 5)
        
        # 策略操作按钮
        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.open_strategy_btn = wx.Button(strategy_box, label="策略目录")
        self.open_strategy_btn.Bind(wx.EVT_BUTTON, self.on_open_strategy)
        btn_sizer.Add(self.open_strategy_btn, 1, wx.EXPAND|wx.RIGHT, 5)
        
        self.edit_strategy_btn = wx.Button(strategy_box, label="编辑策略")
        btn_sizer.Add(self.edit_strategy_btn, 1, wx.EXPAND)
        self.edit_strategy_btn.Bind(wx.EVT_BUTTON,self.on_edit_strategy)
        strategy_sizer.Add(btn_sizer, 0, wx.EXPAND|wx.ALL, 5)
        
        # 日期选择
        date_box = wx.StaticBox(self.left_panel, label="回测日期范围")
        date_sizer = wx.StaticBoxSizer(date_box, wx.VERTICAL)
        
        start_date_sizer = wx.BoxSizer(wx.HORIZONTAL)
        start_date_sizer.Add(wx.StaticText(date_box, label="开始日期:"), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5)
        self.start_date = wx.adv.DatePickerCtrl(date_box, style=wx.adv.DP_DROPDOWN|wx.adv.DP_SHOWCENTURY)
        start_date_sizer.Add(self.start_date, 1, wx.EXPAND)
        date_sizer.Add(start_date_sizer, 0, wx.EXPAND|wx.ALL, 5)
        
        end_date_sizer = wx.BoxSizer(wx.HORIZONTAL)
        end_date_sizer.Add(wx.StaticText(date_box, label="结束日期:"), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5)
        self.end_date = wx.adv.DatePickerCtrl(date_box, style=wx.adv.DP_DROPDOWN|wx.adv.DP_SHOWCENTURY)
        end_date_sizer.Add(self.end_date, 1, wx.EXPAND)
        date_sizer.Add(end_date_sizer, 0, wx.EXPAND|wx.ALL, 5)
        
        # Benchmark选择
        benchmark_box = wx.StaticBox(self.left_panel, label="基准指标")
        benchmark_sizer = wx.StaticBoxSizer(benchmark_box, wx.VERTICAL)

        # 基准代码映射表
        self.benchmark_map = {
            "沪深300": "510300.SH",
            "中证500": "510500.SH",
            "创业板指": "159915.SZ"
        }

        self.benchmark_choice = wx.Choice(benchmark_box, choices=list(self.benchmark_map.keys()))
        #self.benchmark_choice.Bind(wx.EVT_CHOICE, self.on_choice_selected)
        benchmark_sizer.Add(self.benchmark_choice, 0, wx.EXPAND|wx.ALL, 5)
        self.benchmark_choice.SetSelection(0)  # 默认选中第一个选项
        
        # 回测进度条
        self.progress = wx.Gauge(self.left_panel, range=100)
        
        # 启动回测按钮
        self.start_btn = wx.Button(self.left_panel, label="启动回测")
        self.start_btn.Bind(wx.EVT_BUTTON, self.on_start_backtest)
        
        # 停止回测按钮
        self.stop_btn = wx.Button(self.left_panel, label="停止回测")
        self.stop_btn.Bind(wx.EVT_BUTTON, self.on_stop_backtest)
        self.stop_btn.Disable()
        
        # 按钮布局
        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
        btn_sizer.Add(self.start_btn, 1, wx.EXPAND|wx.RIGHT, 5)
        btn_sizer.Add(self.stop_btn, 1, wx.EXPAND)
        
        # 添加左侧组件
        left_sizer.Add(strategy_sizer, 0, wx.EXPAND|wx.ALL, 5)
        left_sizer.Add(date_sizer, 0, wx.EXPAND|wx.ALL, 5)
        left_sizer.Add(benchmark_sizer, 0, wx.EXPAND|wx.ALL, 5)
        left_sizer.Add(self.progress, 0, wx.EXPAND|wx.ALL, 5)
        left_sizer.Add(btn_sizer, 0, wx.EXPAND|wx.ALL, 5)
        
        self.left_panel.SetSizer(left_sizer)
        
        # 右侧面板 - WebView显示结果
        self.right_panel = wx.Panel(self)
        right_sizer = wx.BoxSizer(wx.VERTICAL)
        
        # 创建WebView
        self.webview = webview.WebView.New(self.right_panel)
        right_sizer.Add(self.webview, 1, wx.EXPAND)
        
        self.right_panel.SetSizer(right_sizer)
        
        # 设置主布局比例
        self.main_sizer.Add(self.left_panel, 1, wx.EXPAND)
        self.main_sizer.Add(self.right_panel, 4, wx.EXPAND)
        self.SetSizer(self.main_sizer)

        # 获取当前日期
        today = datetime.today()

        # 设置开始日期（1年前）
        start_date = wx.DateTime()
        start_date.Set(
            day=today.day,
            month=today.month - 1,  # wx.DateTime 月份是 0-11
            year=today.year - 1
        )

        # 设置结束日期（当前日期）
        end_date = wx.DateTime()
        end_date.Set(
            day=today.day,
            month=today.month - 1,  # wx.DateTime 月份是 0-11
            year=today.year
        )

        # 应用到控件
        self.start_date.SetValue(start_date)
        self.end_date.SetValue(end_date)
        
        # 绑定自定义事件
        self.Bind(EVT_BACKTEST_PROGRESS, self.on_backtest_progress)
        self.Bind(EVT_BACKTEST_COMPLETE, self.on_backtest_complete)
        
        # 默认加载策略的HTML
        self.load_default_html()

        if self.strategy_choice.GetCount() > 0:  # 确保有选项
            self.strategy_choice.SetSelection(0)
            self.update_dates_from_task(self.strategy_choice.GetStringSelection())

    def on_strategy_changed(self, event):
        """当策略选择变化时更新日期"""
        selected_strategy = self.strategy_choice.GetStringSelection()
        self.load_default_html()
        self.update_dates_from_task(selected_strategy)
        event.Skip()

    def on_edit_strategy(self, event):
        print('edit')
        #pass
        # wx.MessageBox('功能开发中')
        # #return
        strategy_name = self.strategy_choice.GetStringSelection()
        if not strategy_name:
            strategy_name = self.strategy_choice.GetStrings()[0]

        task = local_tasks[strategy_name]
        from gui.dialog_task import TaskConfigDialog
        dlg = TaskConfigDialog(parent=None,task=task)
        dlg.ShowModal()
        #
        # file_path = f"{strategy_name}.toml"
        # file_path = str(DATA_TASKS.joinpath(file_path).resolve())
        #
        # self.open_file_with_default_editor(file_path)

    def open_file_with_default_editor(self, file_path):
        """用系统默认编辑器打开文件"""
        if not os.path.exists(file_path):
            wx.MessageBox(f"文件不存在: {file_path}", "错误", wx.OK | wx.ICON_ERROR)
            return

        try:
            if platform.system() == "Windows":
                os.startfile(file_path)
            elif platform.system() == "Darwin":  # macOS
                subprocess.run(["open", file_path])
            else:  # Linux
                subprocess.run(["xdg-open", file_path])
        except Exception as e:
            wx.MessageBox(f"无法打开文件: {str(e)}", "错误", wx.OK | wx.ICON_ERROR)


    def update_dates_from_task(self, strategy_name):
        """根据策略名称更新日期控件"""
        if strategy_name in local_tasks.keys():
            task = local_tasks[strategy_name]

            # 解析开始日期
            start_date_str = task.start_date  # 格式: "20100101"
            start_date = datetime.strptime(start_date_str, "%Y%m%d")
            wx_start = wx.DateTime()
            wx_start.Set(
                day=start_date.day,
                month=start_date.month - 1,  # wx月份是0-11
                year=start_date.year
            )
            self.start_date.SetValue(wx_start)

            # 解析结束日期
            end_date_str = task.end_date  # 格式: "20201231"
            if end_date_str == '':
                end_date_str = datetime.now().strftime('%Y%m%d')
            end_date = datetime.strptime(end_date_str, "%Y%m%d")
            wx_end = wx.DateTime()
            wx_end.Set(
                day=end_date.day,
                month=end_date.month - 1,  # wx月份是0-11
                year=end_date.year
            )
            self.end_date.SetValue(wx_end)

    def load_default_html(self):
        """加载默认的策略HTML文件"""
        strategy_name = self.strategy_choice.GetStringSelection()
        if not strategy_name:
            strategy_name = self.strategy_choice.GetStrings()[0]

        html_file = f"{strategy_name}.html"
        html_file = str(config.DATA_REPORTS.joinpath(html_file).resolve())

        #print(html_file)

        if os.path.exists(html_file):
            self.webview.LoadURL(f"file://{os.path.abspath(html_file)}")
        else:
            # 如果文件不存在，显示空白页面或默认页面
            self.webview.SetPage("<html><body><h1>回测结果将显示在这里</h1></body></html>", "")
    
    def on_open_strategy(self, event):
        """打开策略按钮事件处理"""
        strategy = self.strategy_choice.GetStringSelection()
        if not strategy:
            wx.MessageBox("请先选择一个策略", "提示", wx.OK|wx.ICON_INFORMATION)
            return
        
        # 这里应该是打开策略文件的逻辑
        from config import DATA_TASKS

        # 检查目录是否存在
        target_dir = str(DATA_TASKS.resolve())
        if not os.path.exists(str(DATA_TASKS.resolve())):
            wx.MessageBox(f"目录不存在: {target_dir}", "错误", wx.OK | wx.ICON_ERROR)
            return

        # 根据不同操作系统打开目录
        system = platform.system()
        try:
            if system == "Windows":
                os.startfile(target_dir)
            elif system == "Darwin":  # macOS
                os.system(f'open "{target_dir}"')
            else:  # Linux
                os.system(f'xdg-open "{target_dir}"')
        except Exception as e:
            wx.MessageBox(f"无法打开目录: {str(e)}", "错误", wx.OK | wx.ICON_ERROR)

        # 例如：打开策略代码文件或策略配置对话框
        #wx.MessageBox(f"策略目录: {strategy}", "提示", wx.OK|wx.ICON_INFORMATION)

    def on_start_backtest(self, event):
        """启动回测按钮事件处理"""
        if self.backtest_thread and self.backtest_thread.is_alive():
            wx.MessageBox("已有回测正在运行", "提示", wx.OK|wx.ICON_INFORMATION)
            return
        
        # 获取选择的参数
        strategy = self.strategy_choice.GetStringSelection()
        if not strategy:
            wx.MessageBox("请选择一个策略", "错误", wx.OK|wx.ICON_ERROR)
            return
        
        start_date = self.start_date.GetValue().FormatISODate().replace('-','')
        end_date = self.end_date.GetValue().FormatISODate().replace('-','')
        benchmark = self.benchmark_map[self.benchmark_choice.GetStringSelection()]
        
        # 重置进度条
        self.progress.SetValue(0)
        self.start_btn.Disable()
        self.stop_btn.Enable()
        
        # 创建并启动回测线程
        self.backtest_thread = BacktestThread(self, strategy, start_date, end_date, benchmark)
        self.backtest_thread.start()
    
    def on_stop_backtest(self, event):
        """停止回测按钮事件处理"""
        if self.backtest_thread and self.backtest_thread.is_alive():
            self.backtest_thread.stop()
            self.stop_btn.Disable()
            wx.MessageBox("回测已停止", "提示", wx.OK|wx.ICON_INFORMATION)
    
    def on_backtest_progress(self, event):
        """回测进度更新事件处理"""
        self.progress.SetValue(event.progress)
    
    def on_backtest_complete(self, event):
        """回测完成事件处理"""
        self.progress.SetValue(100)
        self.start_btn.Enable()
        self.stop_btn.Disable()

        #self.load_default_html()
        wx.MessageBox("回测成功完成！", "提示", wx.OK | wx.ICON_INFORMATION)
        
        # # 加载回测结果
        # html_file = f"{event.strategy}.html"
        # if os.path.exists(html_file):
        #     self.webview.LoadURL(f"file://{os.path.abspath(html_file)}")
        # else:
        #     wx.MessageBox(f"回测完成，但未找到结果文件: {html_file}", "提示", wx.OK|wx.ICON_INFORMATION)

# 使用示例
if __name__ == "__main__":
    app = wx.App(False)
    frame = wx.Frame(None, title="量化回测工具", size=(1000, 600))
    panel = BacktestPanel(frame)
    frame.Show()
    app.MainLoop()